/*
   Copyright (C) 2011 Roman Belov <romblv@gmail.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "lib/base.h"
#include "lib/io.h"
#include "lang/parser.h"
#include "lang/signal.h"
#include "sim/args.h"
#include "sim/edsim.h"

static void		*default_calc;

int
lib_base_and(struct module *m)
{
	int		arg[2];
	int		val;

	edsim_lib_share_in(m, arg, 2);

	val = arg[0] && arg[1];

	return edsim_lib_share_out(m, 2, val);
}

int
lib_base_or(struct module *m)
{
	int		arg[2];
	int		val;

	edsim_lib_share_in(m, arg, 2);

	val = arg[0] || arg[1];

	return edsim_lib_share_out(m, 2, val);
}

int
lib_base_nand(struct module *m)
{
	int		arg[2];
	int		val;

	edsim_lib_share_in(m, arg, 2);

	val = !(arg[0] && arg[1]);

	return edsim_lib_share_out(m, 2, val);
}

int
lib_base_nor(struct module *m)
{
	int		arg[2];
	int		val;

	edsim_lib_share_in(m, arg, 2);

	val = !(arg[0] || arg[1]);

	return edsim_lib_share_out(m, 2, val);
}

int
lib_base_not(struct module *m)
{
	int		arg[1];
	int		val;

	edsim_lib_share_in(m, arg, 1);

	val = !arg[0];

	return edsim_lib_share_out(m, 1, val);
}

int
lib_base_gate(struct module *m)
{
	int		touch = 0;
	int		arg[2];

	edsim_lib_share_in(m, arg, 2);

	if (arg[1])
		touch += edsim_lib_share_out(m, 2, arg[0]);
	else
		touch += edsim_lib_share_unpull(m, 2);

	return touch;
}

int
lib_base_clock(struct module *m)
{
	int		val;

	val = (glob.run_tick & 1)
			? SIGNAL_PULL_UP
			: SIGNAL_PULL_DOWN;

	return edsim_lib_share_out(m, 0, val);
}

void *
lib_base_get_cacl(const char *lib)
{
	void		*calc;

	if (!strcmp(lib, "base_and"))
		return lib_base_and;
	else if (!strcmp(lib, "base_or"))
		return lib_base_or;
	else if (!strcmp(lib, "base_nand"))
		return lib_base_nand;
	else if (!strcmp(lib, "base_nor"))
		return lib_base_nor;
	else if (!strcmp(lib, "base_not"))
		return lib_base_not;
	else if (!strcmp(lib, "base_gate"))
		return lib_base_gate;
	else if (!strcmp(lib, "base_clock"))
		return lib_base_clock;
	else {
		calc = lib_io_get_cacl(lib);

		return calc;
	}
}

void
lib_base_set_default(void *proc)
{
	default_calc = proc;
}

void *
lib_base_get_default()
{
	return default_calc;
}

